#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <ctime>
#include <cstdarg>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <fstream>
#include <mutex>
#include <pthread.h>
#include "LockGuard.hpp"

#define _SCREEN_TYPE_ 1
#define _FILE_TYPE 2
namespace ns_log
{
    pthread_mutex_t gmutex = PTHREAD_MUTEX_INITIALIZER;
    const std::string DEFAULTSTR = "Log.txt";
    enum
    {
        DEBUG = 1,
        INFO,
        WARNING,
        ERROR,
        FATAL
    };
    struct Logmessage
    {
        std::string _level; // 等级
        pid_t _pid;
        std::string _filename;   // 文件名
        int _filenumber;         // 行号
        std::string _curr_time;  // 获取日志信息出现的时间
        std::string _logmessage; // 信息
    };

    std::string LevelToString(int level)
    {
        switch (level)
        {
        case DEBUG:
            return "DEBUG";
            break;
        case INFO:
            return "INFO";
            break;
        case WARNING:
            return "WARNING";
            break;
        case ERROR:
            return "ERROR";
            break;
        case FATAL:
            return "FATAL";
            break;
        default:
            return "UNKNOW";
            break;
        }
    }
    std::string GetCurrTime()
    {
        time_t now_time = time(nullptr);
        struct tm *curr_time = localtime(&now_time);
        // 转换为string格式
        char buf[128];
        snprintf(buf, sizeof(buf), "%d-%02d-%02d %02d:%02d:%02d",
                                   curr_time->tm_year + 1900
                                   , curr_time->tm_mon + 1
                                   , curr_time->tm_mday
                                   , curr_time->tm_hour
                                   , curr_time->tm_min
                                   , curr_time->tm_sec);
        return buf;
    }
    class Log
    {
        void LogMsgToScreen(const Logmessage &logmsg)
        {
            printf("[%s][%d][%s][%d][%s] %s",
                    logmsg._level.c_str()
                    , logmsg._pid
                    , logmsg._filename.c_str()
                    , logmsg._filenumber
                    , logmsg._curr_time.c_str()
                    , logmsg._logmessage.c_str());
        }
        void LogMsgToFile(const Logmessage &logmsg)
        {
            char buf_info[2048] = "\0";
            snprintf(buf_info, sizeof(buf_info), "[%s][%d][%s][%d][%s] %s", 
                                                logmsg._level.c_str()
                                                , logmsg._pid
                                                , logmsg._filename.c_str()
                                                , logmsg._filenumber
                                                , logmsg._curr_time.c_str()
                                                , logmsg._logmessage.c_str());
            /*--系统调用版本--*/
            // int fd = open(_logfile.c_str(),O_CREAT | O_WRONLY | O_APPEND,0666);
            // if(fd < 0)
            // {
            //     perror("open");
            //     return;
            // }
            // write(fd,buf_info,sizeof(buf_info));

            /*--c++提供的fstream--*/
            std::ofstream out;
            out.open(_logfile, std::ios::out | std::ios::app | std::ios::binary);
            if (!out.is_open())
                return;
            out.write(buf_info, sizeof(buf_info));
            out.close();
        }
        void FlushLogMsg(const Logmessage &logmsg)
        {
            // c++11的锁
            //  _mutex.lock();
            // RAII类型的锁
            LockGuard _mutex(&gmutex);
            // 过滤逻辑 --TODO
            switch (_type)
            {
            case _SCREEN_TYPE_:
                LogMsgToScreen(logmsg);
                break;
            case _FILE_TYPE:
                LogMsgToFile(logmsg);
                break;
            }
            // _mutex.unlock();
        }

    public:
        Log(const std::string &logfile = DEFAULTSTR) : _logfile(logfile), _type(_SCREEN_TYPE_)
        {
        }
        void ModPrintFormat(int type)
        {
            _type = type;
        }
        void LogMessage(int level, std::string filename, int filenumber, const char *format, ...) // 注意-->可变函数参数
        {
            Logmessage msg;
            msg._level = LevelToString(level);
            msg._filename = filename;
            msg._pid = getpid();
            msg._filenumber = filenumber;
            msg._curr_time = GetCurrTime();
            // 注意：取出可变参数的固定写法
            va_list _ap;           // 创建变量,本质是一个指针
            va_start(_ap, format); // 将参数列表中离...最近的确定的参数传入
            char log_info[512];
            vsnprintf(log_info, sizeof(log_info), format, _ap);
            va_end(_ap); // 销毁_ap
            msg._logmessage = log_info;
            FlushLogMsg(msg);
        }
        ~Log()
        {}
    private:
        int _type;
        std::string _logfile;
        // std::mutex _mutex;
    };

    Log lg;
#define LOG(level, format, ...)                                          \
    do                                                                   \
    {                                                                    \
        lg.LogMessage(level, __FILE__, __LINE__, format, ##__VA_ARGS__); \
    } while (0)

#define LOGTOSCREEN(level, format, ...)                \
    do                                    \
    {                                     \
        lg.ModPrintFormat(_SCREEN_TYPE_); \
        lg.LogMessage(level, __FILE__, __LINE__, format, ##__VA_ARGS__); \
    } while (0)

#define LOGTOFILE(level)               \
    do                                 \
    {                                  \
        lg.ModPrintFormat(_FILE_TYPE); \
    } while (0) 

}